package logic;

import java.util.List;
import java.util.LinkedList;

public class EBNFClass{
    private List<SintaxRule> sr;
    private String id;
    private List<Simbol> simbols;

    public EBNFClass (){
	this.sr=new LinkedList<SintaxRule>();
	this.id="";
    }
    
    public EBNFClass(String id){
	this.id=id;
	this.sr=new LinkedList<SintaxRule>();
	this.simbols=new LinkedList<Simbol>();
    }

    public EBNFClass(String id, List<SintaxRule> sr){
	this.id=id;
	this.sr=sr;
	this.simbols=new LinkedList<Simbol>();
    }
    
    public EBNFClass(String id, List<Simbol> simbols, List<SintaxRule> sr){
	this.id=id;
	this.sr=sr;
	this.simbols=simbols;
    }

    public List<Simbol> getSimbols(){
	return this.simbols;
    }

    public List<SintaxRule> getSintaxRule(){
	return this.sr;
    }

    public String getId(){
	return this.id;
    }

    public void setId(String id){
	this.id=id;
    }

    public void addSR(SintaxRule s){
	this.sr.add(s);
    }

    public void addSimbol(Simbol s){
	this.simbols.add(s);
    }

    public void setType(String type){
	for(int i=0;i<simbols.size();i++)
	    simbols.get(i).setType(type);
    }
    
    public void addSimbols(EBNFClass e2){
	for(int i=0;i<e2.getSimbols().size();i++)
	    this.addSimbol(e2.getSimbols().get(i));
    }
    /*
    @Override public String toString(){
	return "" + getId() + "\n";
    }
    */
    private String getConwayById(String id, String node1, String node2, String src){
	String conway="";
	SintaxRule srule = null;
	for(int i=0;i<sr.size() && srule==null;i++){
	    if(sr.get(i).getId().equals(id))
		srule=sr.get(i);
	}
	if(srule!=null)
	    for(int i=srule.getProduction().size()-1;i>=0;i--)
	    	conway+=srule.getProduction().get(i).getConway(node1,node2,i,src)+"\n";

	return conway;
    }

    public List<String> getConway(String domain){
	String conway="";
	List<String> conways = new LinkedList<String>();

	if (domain.equals("all"))
	    for(int i=0;i<sr.size();i++){
			conway="ebnfnodein [shape=point];\n";
			conway+="ebnfnodeout [shape=point];\n";
			conway+=getConwayById(sr.get(i).getId(), "ebnfnodein", "ebnfnodeout", getId()) + "\n";
			conways.add(conway);
	    }
	else{
	    conway+=getConwayById(domain, "ebnfnodein", "ebnfnodeout", getId());
	    conways.add(conway);
	}
	
	return conways;
    }


    public List<SintaxRule> EBNF2GLC(){
		List<SintaxRule> srs = new LinkedList<SintaxRule>();
		int srss=0, sims=0, innerpssize=0;
		Production p; //, innerp;
		List<Production> innerps;
		SintaxRule s;
	
		for(int k=0;k<this.sr.size();k++){
		    s = new SintaxRule(this.sr.get(k).getId());
		    for(int i=0;i<this.sr.get(k).getProduction().size();i++){
				p=new Production();
				
				sims=this.sr.get(k).getProduction().get(i).getSimbols().size()-1;
				srss=this.sr.get(k).getProduction().get(i).getSRSimbols().size()-1;
				/*sims=0;
				srss=0;*/
				for(int j=0;j<this.sr.get(k).getProduction().get(i).getSimbols().size()+this.sr.get(k).getProduction().get(i).getSRSimbols().size();j++){
				    if(this.sr.get(k).getProduction().get(i).getSRSimbols().size() > 0 && srss>=0 && this.sr.get(k).getProduction().get(i).getSRSimbols().get(srss).getPosition()==j){
				    	p.addSimbol(new Simbol("AUX"+this.sr.get(k).getId()+j,"nonterminal"));
						addSimbol(new Simbol("AUX"+this.sr.get(k).getId()+j,"nonterminal"));
						innerps=new LinkedList<Production>();
						for(int n=0;n<this.sr.get(k).getProduction().get(i).getSRSimbols().get(srss).getProduction().size();n++)
							innerps.add(this.sr.get(k).getProduction().get(i).getSRSimbols().get(srss).getProduction().get(n).clone());
						innerpssize=innerps.size();
						if(this.sr.get(k).getProduction().get(i).getSRSimbols().get(srss).getType().equals("repeated")){
							/* De esta forma hay 0 o mas repeticiones */
							for(int m=0;m<innerpssize;m++)
								innerps.get(m).addSimbol(new Simbol("AUX"+this.sr.get(k).getId()+j));
							innerps.add(new Production());
							/* De esta forma debe haber al menos una repeticion */
							/*
						    for(int m=0;m<innerpssize;m++){
								innerp=innerps.get(m).clone();
								innerp.addSimbol(new Simbol("AUX"+this.sr.get(k).getId()+j));
								innerps.add(innerp);
						    }
							*/
						}
						if(this.sr.get(k).getProduction().get(i).getSRSimbols().get(srss).getType().equals("optional")){
						    innerps.add(new Production());
						}
						srs.add(new SintaxRule("AUX"+this.sr.get(k).getId()+j,innerps));
						srss--;
				    }else if(this.sr.get(k).getProduction().get(i).getSimbols().size() > 0 && sims>=0){
				    	p.addSimbol(this.sr.get(k).getProduction().get(i).getSimbols().get(sims));
						sims--;
				    }
				}
				p.reverse();
				s.addProduction(p);
		    }
		    srs.add(s);
		}
		
		return srs;
    }


    public String toString(){
	String termin="";
	String nontermin="";
	boolean haytermin=false;
	boolean haynontermin=false;

	String s="ebnf "+getId()+"{\n";
	for(int i=simbols.size()-1;i>=0;i--){
	    if(simbols.get(i).getType()=="terminal"){
		if(haytermin==true)termin+=", ";
		termin+=simbols.get(i).getValue();				
		haytermin=true;
	    }
	    if(simbols.get(i).getType()=="nonterminal"){
		if(haynontermin==true)nontermin+=", ";
		nontermin+=simbols.get(i).getValue();
		haynontermin=true;
	    }
	}

	if(haytermin==true)s+="terminal "+termin+";\n";
	if(haynontermin==true)s+="nonterminal "+nontermin+";\n";			

	for(int i=sr.size()-1;i>=0;i--)
	    s+=sr.get(i).toString()+"\n";

	s+="}\n";
	return s;
    }	

}